Der große Vorteil dieser Art von Webapplikation ist, dass sie sich für Benutzer:innen im Idealfall anfühlen wie Desktopapplikationen. Es gibt also keine Ladezeiten zwischen den einzelnen Sichten. Der größte Nachteil ist die initiale Ladezeit einer solchen Applikation. Der Grund hierfür ist, dass nicht nur die aktuelle Sicht und ihre Daten geladen werden müssen, sondern die komplette Applikation mit allen Sichten. Außerdem kommt noch das jeweils verwendete Framework hinzu, alles keine wirklichen Leichtgewichte. Der Lebenszyklus einer solchen Applikation hat eine weitere Eigenheit parat: Normalerweise rendert das Framework seine Komponenten in einem leeren Zustand und kommuniziert anschließend mit einer Serverschnittstelle, die die Daten zur Anzeige bereitstellt. Sobald die Daten im Frontend vorliegen, werden die entsprechenden Komponenten neu gerendert.
Wie aber sieht der Ablauf aus Sicht der BenutzerInnen aus? Ich gebe die Adresse der Applikation im Browser ein und bestätige. Ich sehe erstmal eine weiße Seite, warte, dann den Rahmen der Applikation, keine Daten, und plötzlich ist alles da. Eine gute User Experience funktioniert anders. Natürlich kann ich mit dem Browsercache oder einem Service Worker etwas tricksen. Das hilft mir aber beim initialen Laden der Applikation nicht. Der zweite und alle folgenden Ladevorgänge sind jedoch deutlich schneller. Ein weiterer Trick, den Sie anwenden können, um den initialen Ladevorgang zu beschleunigen, ist der Einsatz von Lazy Loading. Dabei laden Sie zu Beginn nicht alle Komponenten, die in Ihrer Applikation vorkommen können, sondern nur die, die Sie zu Beginn wirklich benötigen. Das sorgt für eine kleinere Bundle-Größe und damit für eine schnellere Ladezeit. Aber das alles ist lediglich Kosmetik und versucht, den Benutzer:innen Performance vorzugaukeln. Doch es muss nicht alles fake sein, denn moderne Frameworks beinhalten Features, die ganz andere Konzepte erlauben. Die Rede ist von Server-side Rendering und Static Site Generation. Beide Konzepte nehmen wir kurz unter die Lupe und stellen uns insgeheim die Frage, ob wir nicht vielleicht wieder zum guten alten PHP zurückgehen, wenn es darum geht, dynamische Webseiten serverseitig zu rendern.
Server-side Rendering
Server-side Rendering, bzw. die geläufigere Kurzvariante SSR, bezeichnet einen Workflow, bei dem die Sicht einer Single Page Application serverseitig gerendert und an den Browser ausgeliefert wird. Damit das funktionieren kann, braucht es natürlich eine entsprechende Infrastruktur. Die Frontend-Frameworks sind entweder in JavaScript oder TypeScript implementiert und mehr oder weniger fest mit dem DOM des Browsers verzahnt. Beim SSR gibt es die DOM-Komponente in dieser Form nicht. Und auch die übrige Laufzeitumgebung unterscheidet sich deutlich vom Browser. In den meisten Fällen kommt Node.js als Basis zum Einsatz. Diese Wahl ist naheliegend, da Node.js die gleiche JavaScript-Engine wie Chrome und Edge verwendet. Das Ziel von SSR ist es, jetzt mit Node.js eine HTML-Struktur zu erzeugen, die der Struktur der fertig gerenderten Applikation im Frontend entspricht. Also nicht das typische leere div-Element, das sonst vom Webserver ausgeliefert wird und in das dann die Applikation mit clientseitigem JavaScript gebaut wird. Dabei geht es nicht nur um die leere Rahmenstruktur der leer gerenderten Komponenten, sondern um die fertige Applikation mit allen Nutzdaten. So etwas zu erreichen, ist jetzt kein Kunststück, das können Sie auch mit traditionellen serverseitigen Programmiersprachen und Frameworks, Sie benötigen kein zusätzliches Frontend-Framework dazu.
Interessant wird das Ganze erst durch die Tatsache, dass nach der Auslieferung und der initialen Darstellung der Struktur im Browser das Frontend-Framework die Kontrolle über die HTML-Struktur übernimmt. Dieser Prozess wird Hydration genannt. Das bedeutet, dass SSR im Prinzip auch nichts anderes als ein Fake ist. Nach der Auslieferung können die Benutzer:innen erstmal nichts mit der Applikation anfangen, da keinerlei Interaktion (abgesehen von den Standard-HTML-Elementen) möglich ist. Erst, wenn das Framework die Kontrolle übernommen hat, entspricht die Applikation dem Stand der regulären Single Page Application, also nachdem alle Daten geladen sind.
Der Effekt für die Benutzer:innen ist in der Regel jedoch deutlich spürbar. SSR-Applikationen werden deutlich schneller ausgeliefert beziehungsweise liefern deutlich schneller visuelle Ergebnisse, mit denen die Benutzer:innen arbeiten können. Ein weiterer Nutznießer dieser Technologie sind die Suchmaschinen beziehungsweise die Personen, die Applikationen für Suchmaschinen optimieren. Da die Applikation nicht mehr aus einem leeren div-Element besteht, sondern aus tatsächlichem Inhalt, ist es für Suchmaschinen einfacher, die Applikation zu indexieren, wofür sie normalerweise ordentlich Pluspunkte verteilen.
Die einzelnen Schritte, die erledigt werden müssen, um eine Darstellung im Browser zu erreichen, sind bei traditionellen Browserapplikationen und beim SSR die gleichen, nur die Stelle, an der sie ausgeführt werden, unterscheidet sich. Beim SSR führen Sie das Framework serverseitig mit Node.js aus und laden die Daten, die Sie zur Darstellung benötigen, ebenfalls serverseitig. Anschließend wird die Applikation an den Browser ausgeliefert. Der Vorteil an dieser Stelle ist, dass die Benutzer:innen viel schneller die fertige Applikation sehen, auch, wenn sie nicht direkt damit interagieren können. Außerdem können Sie potenziell Overhead einsparen, der durch die Requests für das nachgelagerte Laden der Daten entsteht.
SSR in der Praxis
Doch wie setzen die einzelnen Frameworks SSR konkret um? Werfen wir doch einmal einen Blick auf die verschiedenen Implementierungen. Fangen wir mit Angular an:
-
Angular: Das Framework verschiebt die Verantwortlichkeit für SSR in ein Subprojekt mit dem Namen Angular Universal. Mit diesem können Sie Ihre Angular-Applikation beispielsweise in einer Express.js-Applikation serverseitig rendern lassen.
-
Vue: In Vue ist SSR etwas enger mit dem Framework selbst verankert. Sie können hier createSSRApp aus dem vue-Paket nutzen, um Ihre Applikation aufzubauen. Die eigentliche Transformation in eine Struktur, die Sie an Browser ausliefern können, übernimmt dann die renderToString-Funktion aus dem vue/server-renderer-Paket.
-
React: React verfügt ähnlich wie Vue über ein separates Unterpaket, das Ihnen die Grundlagen für SSR bietet. Mit Funktionen wie renderToString oder renderToStaticMarkup aus dem react-dom/server-Paket können Sie Strukturen erzeugen, die Sie über Node.js an Ihre Benutzer:innen ausliefern können.
-
Svelte: Svelte ist ebenfalls für den Betrieb in einer SSR-Applikation vorbereitet. Wobei hier sehr häufig auf ein zusätzliches Werkzeug mit dem Namen SvelteKit zurückgegriffen wird, das neben zahlreichen weiteren Hilfsmitteln und Optimierungen auch SSR unterstützt.
Ähnlich wie bei Svelte mit SvelteKit ist es auch in anderen Frameworks durchaus üblich, dass Sie SSR in Ihrer Applikation nicht selbst aufsetzen, sondern auf bestehende Werkzeuge setzen. Ein typisches Beispiel ist im Fall von React das Framework Next.js.
Sie können in einem weiteren Schritt sogar die gerenderte Applikation serverseitig zwischenspeichern, also cachen. Das hat den Vorteil, dass bei der Auslieferung das Rendern und Laden der Daten entfällt und die angeforderte Struktur sofort ausgeliefert wird. Hierbei handelt es sich jedoch in der Regel um ein theoretisches Konstrukt, da in den meisten Fällen individuelle Informationen miteinfließen, die erst nach einem Log-in verfügbar sind. In diesem Fall müssen Sie zumindest dafür sorgen, dass das Laden der Daten vom Rest abgekoppelt ist, um den Schutz sensibler Daten zu gewährleisten.
Auf die Idee, die Ausgabe des SSR in einen Cache zu schreiben, sind vor uns auch schon andere Personen gekommen und haben dafür den Begriff Static Site Generation geprägt.
Static Site Generation
Bei der Static Site Generation, abgekürzt SSG, erzeugt ein Serverprozess statischen HTML-Code aus Templates und dynamischen Daten. Im Gegensatz zum SSR, bei dem der Serverprozess immer laufen muss, wird er bei der SSG nur zum Erzeugen der Strukturen benötigt. Das Ergebnis, also das gerendertes HTML, können Sie mit einem statischen Webserver ausliefern. Für die verschiedenen Frameworks gibt es jeweils eigene Werkzeuge für die SSG.
Für React sind die populärsten Hilfsmittel beispielsweise Gatsby oder Next.js. In Vue können Sie auf Nuxt oder VuePress setzen. Eine weit verbreitete Lösung für SSG unter Angular ist Scully.
Was lernen wir daraus?
An Single Page Applications ist im Moment kein Vorbeikommen im Web. Allerdings hat diese Art der Applikationsarchitektur nicht nur Vorteile, sondern auch ein paar entscheidende Nachteile. So ist eine SPA im Vergleich zu einer traditionellen Webseite ein wahres Schwergewicht, da Sie nicht nur das HTML, CSS und JavaScript der aktuellen Sicht, sondern die komplette Applikation herunterladen müssen. Eines der wichtigsten Ziele von Entwickler:innen ist es, den initialen Ladevorgang einer Webapplikation zu kurz wie möglich zu halten. Methoden wie Lazy Loading können dabei helfen, die Bundle Size zu verkleinern. SSR geht hier einen entscheidenden Schritt weiter, indem der Server die Rolle des Browsers einnimmt und die Applikation so weit vorrendert, dass das Framework nur noch die Kontrolle über die fertige Struktur übernehmen muss. In diesem Fall muss der Serverprozess immer aktiv sein und die eingehenden Anfragen der Benutzer beantworten. Dieses Problem löst die SSG, indem es die einzelnen Seiten statisch vorgeneriert, die Sie dann über einen Webserver ausliefern können.